package cn.imokay.juc.lock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 可重入锁
 * 当monitor enter时，如果锁对象计数器时0，表明灭有线程持有该锁，当前线程可里立马持有该锁，并将owner改为当前线程，
 * 计数器不为零时，当owner为当前线程时，则继续持有该锁，计数器加一，当monitor exit时，计数器减1，当计数器减到0时，表明释放该锁
 */
public class ReenterLockDemo {
    public static void main(String[] args) {
        test1();

        m1();

        test2();

    }

    private static void test2() {
        ReentrantLock lock = new ReentrantLock();
        new Thread(()->{
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "\t 外层执行");
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + "\t 中层执行");
                    lock.lock();
                    try {
                        System.out.println(Thread.currentThread().getName() + "\t 内层执行");
                    }finally {
                        lock.unlock();
                    }
                }finally {
                    lock.unlock();
                }
            }finally {
                lock.unlock();
            }
        }).start();
    }

    private synchronized static void m1() {
        System.out.println(Thread.currentThread().getName() + "\t---m1 come in");
        m2();
        System.out.println(Thread.currentThread().getName() + "\t---m1 end");
    }

    private synchronized static void m2() {
        System.out.println(Thread.currentThread().getName() + "\t---m2 come in");
        m3();
        System.out.println(Thread.currentThread().getName() + "\t---m2 end");
    }

    private synchronized static void m3() {
        System.out.println(Thread.currentThread().getName() + "\t---m3 come in");
        System.out.println(Thread.currentThread().getName() + "\t---m3 end");
    }

    private static void test1() {
        Object o = new Object();
        new Thread(()->{
            System.out.println(Thread.currentThread().getName() + "\t---synchronized演示1");
            synchronized (o){
                System.out.println(Thread.currentThread().getName() + "\t---外层调用");
                synchronized (o){
                    System.out.println(Thread.currentThread().getName() + "\t---中层调用");
                    synchronized (o){
                        System.out.println(Thread.currentThread().getName() + "\t--内层调用");
                    }
                }
            }
        }).start();
    }
}
